#ifndef STRUCTS_H
#define STRUCTS_H

#include "main.h"

// Repräsentiert einen Eintrag in der Tabelle
struct IDT_Eintrag {
	unsigned short basis_low;
	unsigned short kSegment; // Kernel Segment
	unsigned char garbage;  // Speicherverschwendung, immer 0!
	unsigned char flags;
	unsigned short basis_high;
} __attribute__((packed));

// Zeigt auf den Anfang der Tabelle ... in lesbarer Form
struct IDT_Pointer {
	unsigned short limit;
	unsigned int basis;
} __attribute__((packed));

// Auch bekannt als cpu_state
struct stack_frame {
    unsigned int gs, fs, es, ds;
    unsigned int edi, esi, ebp, _esp, ebx, edx, ecx, eax;
    unsigned int interrupt, error;
    unsigned int eip, cs, eflags, esp, ss;
};

// Memorymap - bekommen wir von GRUB
struct mbs_mmap {
	uint64_t BaseAddr; // Basisadresse des Speicherbereichs
	uint64_t Length;   // Länge des Speicherbereichs
	uint32_t Type;     // Typ des Speicherbereichs (1 = frei, sonst belegt)
} __attribute__ ((packed));

// Dieses Ding bekommen wir von GRUB
struct multiboot_info {
	uint32_t mbs_flags;
	uint32_t mbs_mem_lower;
	uint32_t mbs_mem_upper;
	uint32_t mbs_bootdevice;
	char    *mbs_cmdline;
	uint32_t mbs_mods_count;
	uint32_t mbs_mods_addr;
	uint32_t mbs_syms;
	uint32_t mbs_mmap_length;
	uint32_t mbs_mmap_addr;
	uint32_t mbs_drives_length;
	uint32_t mbs_drives_addr;
	uint32_t mbs_config_table;
	char    *mbs_boot_loader_name;
	uint32_t mbs_apm_table;
} __attribute__ ((packed));

struct task {
	struct stack_frame *sf;
	struct task *next;
	uint8_t *stack;
	uint8_t *userstack;
	int argc;
	char **argv;
	int priority;
	int ticks; // 1 Tick = 5ms
	int retval;
	pid_t pid;
	pid_t parent;
	BOOL running;
	BOOL destroy;   // Wenn dieser Wert TRUE ist, wird er beim nächsten Aufruf gelöscht
	uint32_t vaddr; // Das Programm will an diese Adresse gemappt werden
	uint32_t paddr; // Und liegt physikalisch da und ist
	uint32_t size;  // x Bytes groß
	uint16_t flags; // Hat nichts mit den Flags aus sf zu tun!
};

// Header für freien Speicher - 12 Byte lang
struct alloc_header {
	uint16_t Magic;			// Wenn die Magic nicht stimmt gabs nen Buffer Overflow
	size_t Speicher;		// Freier Speicher an dieser Stelle
	BOOL used;			// Ist der Speicher in Gebrauch?
	struct alloc_header *next;	// Pointer auf den nächsten Header
};

// Tastatur Struktur
struct keyboard_struct {
	char input;	 // Zeichen
	uint8_t code;    // Scancode
	BOOL key_lshift; // Status diverser Funktionstasten
	BOOL key_rshift;
	BOOL key_lalt;
	BOOL key_ralt;
	BOOL key_lctrl;
	BOOL key_rctrl;
	BOOL key_lwin;
	BOOL key_rwin;
	BOOL key_context;
	BOOL key_capslock;
	BOOL key_numlock;
	BOOL key_scrolllock;
	BOOL pressed;	// Ist die Taste gerade gedrückt oder losgelassen worden?
} __attribute__ ((packed));

// Eintrag im virtuellen Dateisystem
struct fs_entry {
	char name[64];		// Name der Datei/Ordners
	char flags;		// Bit 0 = Ordner, Bit 1 = Systemdatei, Bit 2 = virtuell
	struct fs_entry *next;  // Nächster Eintrag
	struct fs_entry *parent;// Ordner, in dem sich die Datei/Ordner befindet
	char driver;		// Welcher Treiber soll verwendet werden?
	uint32_t userdata;	// Dieses Feld steht dem Treiber frei zur Verfügung
	uint32_t id;		// Interne ID Nummer des Knotens
	uint32_t children;	// Nur für Ordner: Menge der enthaltenen Einträge
} __attribute__ ((packed));

// Die bekannte FILE Struktur (Hat nichts mit anderen Implementationen zu tun!)
typedef struct {
	handle_t handle; // Handlenummer - Intern!
	char driver;	 // Treibernummer
	size_t fpos;	 // Dateiposition
	char access;	 // Zugriffsparameter
	uint32_t userdata;	// Dieses Feld steht dem Treiber frei zur Verfügung
} __attribute__ ((packed)) FILE;

typedef struct {
	long d_ino;			// Inode Nummer
	unsigned short d_reclen;	// Länge des Eintrags
	unsigned short d_namlen;	// Länge des Namens 
	char *d_name;			// Nullterminierter Name des Eintrags
} dirent;

typedef struct {
	uint32_t magic;			// Zum Schutz damit das Programm keinen Müll übergibt, siehe DIR_MAGIC
	struct fs_entry *parent;	// Zeigt auf den Ordner
	struct fs_entry *cur;		// Zeigt auf den aktuellen Eintrag
	dirent *ptr;
} DIR;

/** Ext2 Structs **/

typedef struct {
	uint32_t s_inodes_count;	// Anzahl der iNodes
	uint32_t s_blocks_count;	// Anzahl der Blöcke
	uint32_t s_r_blocks_count;	// Anzahl der reservierten Blöcke (Damit das FS nicht überfüllt)
	uint32_t s_free_blocks_count;	// Anzahl freier Blöcke
	uint32_t s_free_inodes_count;	// Anzahl freier iNodes
	uint32_t s_first_data_block;	// Erster Datenblock, ist also der Block, der den Superblock enthält
	uint32_t s_log_block_size;	// Größe eines Blocks (Blockgröße = 1024 << s_log_block_size)
	int      s_log_frag_size;	// Größe eines Fragments (Wenn positiv: Fragmentgröße = 1024 << s_log_frag_size, wenn negativ: Fragmentgröße = 1024 >> -s_log_frag_size)
	uint32_t s_blocks_per_group;	// Blockanzahl in einer Gruppe
	uint32_t s_frags_per_group;	// Fragmentanzahl in einer Gruppe
	uint32_t s_inodes_per_group;	// iNodeanzahl in einer Gruppe
	uint32_t s_mtime;		// Zeit, wann das FS das letzte mal gemountet wurde (Unix Zeit)
	uint32_t s_wtime;		// Zeit, wann das letzte auf das FS schreibend zugegriffen wurde
	uint16_t s_mnt_count;		// Anzahl, wie oft das FS schon gemountet wurde
	short    s_max_mnt_count;	// Maximale Anzahl, die das FS gemountet werden darf, bevor ein Check nötig ist
	uint16_t s_magic;		// Signatur = 0xEF53
	uint16_t s_state;		// Zeigt an, ob das FS nach dem letzten mount richtig entladen wurde
	uint16_t s_errors;		// Gibt an, was passieren soll, wenn ein Fehler auftritt
	uint16_t s_minor_rev_level;	// Minore Versionsnummer
	uint32_t s_lastcheck;		// Zeit des letzten FS Checks (Unix Zeit)
	uint32_t s_checkinterval;	// Zeitintervall, nach dem das FS gecheckt werden muss (Unix Zeit)
	uint32_t s_creator_os;		// Gibt an, welches Betriebssystem dieses FS erstellt hat
	uint32_t s_rev_level;		// Versionsnummer
	uint16_t s_def_resuid;		// Der Benutzer mit dieser ID kann auch die reservierten Blöcke benutzen
	uint16_t s_def_resgid;		// Die Benutzer in dieser Gruppe können die reservierten Blöcke benutzen
	// EXT2_DYNAMIC_REV Spezifisch (Revision 1)
	uint32_t s_first_ino;		// Zeigt auf den ersten benutzbaren iNode (Rev 0: immer 11)
	uint16_t s_inode_size;		// Größe einer iNode Struktur (Rev 0: immer 128Bytes)
	uint16_t s_block_group_nr;	// Zeigt auf eine Blockgruppe, die ein Backup des Superblocks enthält
	uint32_t s_feature_compat;	// Diese Bitmaske zeigt, welche Funktionen vom FS Treiber bereit gestellt werden *können*
	uint32_t s_feature_incompat;	// Diese Bitmaske zeigt, welche Funktionen vom FS Treiber bereit gestellt werden *müssen*
	uint32_t s_feature_ro_compat;	// Wenn eine der Funktionen nicht unterstützt werden, muss das FS als Read-Only gemountet werden
	char     s_uuid[16];		// Eine möglichst einmalige Nummer
	char     s_volume_name[16];	// Der Name des FS (Meistens nicht benutzt)
	char     s_last_mounted[64];	// Pfad, an dem das FS als letztes gemountet wurde (Meistens nicht benutzt)
	uint32_t s_algo_bitmap;		// Benutzte Kompressions Algorithmen
	// Performance
	char  s_prealloc_blocks;	// Anzahl der Blöcke, die für eine neue Datei reserviert werden sollten (nicht zwingend)
	char  s_prealloc_dir_blocks;	// Anzahl der Blöcke, die für ein neues Verzeichniss reserviert werden sollten
	short aligner_1;
	// Journaling
	char  s_journal_uuid[16];	// Eindeutige ID des Journaling Superblocks
	int   s_journal_inum;		// iNode der Journalingdatei
	int   s_journal_dev;		// Gerätenummer der Journalingdatei
	int   s_last_orphan;		// Zeigt auf den ersten iNode, der gelöscht werden sollte (???)
	// Directory Indexing
	uint32_t s_hash_seed[4];	// Seed für einen Hash Algorithmus (Nicht unterstützt)
	char  s_def_hash_version;	// Version des Hash Algorithmuses, die benutzt werden soll
	char  aligner_2;
	short aligner_3;
	//Other
	int   s_default_mount_options;	// Standart Mountoptionen für dieses FS (???)
	int   s_first_meta_bg;		// Vermutlich nur bei Ext3 verwendet
	// Weitere 760 unbenutzte Bytes
} __attribute__ ((packed)) ext_superblock_t;

typedef struct {
	uint16_t i_mode;	// Beschreibt die Zugriffsrechte und andere Eigenschaften dieses iNodes
	uint16_t i_uid;		// Benutzer ID des Eigentümers
	uint32_t i_size;	// Enthält in Revision 1 die unteren 32 Bits der Dateigröße
	uint32_t i_atime;	// Zeitpunkt des letzten Zugriffs (Unix Zeit)
	uint32_t i_ctime;	// Zeitpunkt der Erstellung des iNodes (Unix Zeit)
	uint32_t i_mtime;	// Zeitpunkt der letzten Änderung am iNode (Unix Zeit)
	uint32_t i_dtime;	// Zeitpunkt, an dem dieser iNode gelöscht wurde (Unix Zeit)
	uint16_t i_gid;		// Gruppen ID der Eigentümer
	uint16_t i_links_count;	// Link Counter. Zeigt an, wie oft diese Datei referenziert wird (Meistens 1)
	uint32_t i_blocks;	// Anzahl der Blöcke, die für diesen Eintrag reserviert sind (Egal ob benutzt oder nicht)
	uint32_t i_flags;	// Flags, die anzeigen, wie mit diesem Eintrag umgegangen werden soll
	uint32_t i_osd1;	// BS spezifisch
	uint32_t i_block[15];	// Zeigt auf die Blöcke, die diesem Eintrag zugeordnet sind
	uint32_t i_generation;	// Dateiversion, wird von NFS benutzt
	uint32_t i_file_acl;	// Zeigt auf einen Block, der erweiterte Attribute enthält
	uint32_t i_dir_acl;	// Enthält die oberen 32 Bits der Dateigröße
	uint32_t i_faddr;	// Unbenutzt, zeigt eigentlich auf einen Block der das Dateifragment enthält
	char     i_osd2[12];	// BS spezifisch
} __attribute__ ((packed)) ext_inode_table_t;

typedef struct {
	uint32_t bg_block_bitmap;	// Block ID des ersten Blocks der Block Bitmap dieser Gruppe
	uint32_t bg_inode_bitmap;	// Block ID des ersten Blocks der iNode Bitmap dieser Gruppe
	uint32_t bg_inode_table;	// Block ID des ersten Blocks der iNode Tabelle dieser Gruppe
	uint16_t bg_free_blocks_count;	// Freie Blöcke in dieser Gruppe
	uint16_t bg_free_inodes_count;	// Freie iNodes in dieser Gruppe
	uint16_t bg_used_dirs_count;	// Anzahl von iNodes in dieser Gruppe, die ein Verzeichniss darstellen
	uint16_t bg_pad;		// Padding/Aligning
	char     bg_reserved[12];	// Reserviert
} __attribute__ ((packed)) ext_group_desc_t; // Block Group Descriptor Table

typedef struct {
	uint32_t inode;		// iNode Nummer des Eintrags. Wenn der Wert = 0 ist, ist dieser Eintrag nicht benutzt!
	uint16_t rec_len;	// Länge dieses Eintrags. Muss 4 aligned sein.
	uint8_t  name_len;	// Länge des Namens
	uint8_t  file_type;	// Flags
	char     *name;		// Name des Eintrags (Laut Tyndur nicht NULL terminiert)
} __attribute__ ((packed)) ext_linked_list_dir_t;

/** ELF Strukturen **/

typedef struct {
	
} __attribute__ ((packed)) elf_header_t;

#endif
